home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / doom / chasecam.zip / QC106.ZIP / hook.qc < prev    next >
Text File  |  1997-04-20  |  12KB  |  419 lines

  1. //====================================================================
  2. //
  3. // SWINGING GRAPPLING HOOK            by: Perecli Manole AKA Bort
  4. //
  5. //====================================================================
  6. // Aside from this new file, the following are the modifications
  7. // done to id's original source files:
  8. //--------------------------------------------------------------------
  9. // File: Progs.src
  10. // Location: before the "weapons.qc" line
  11. // Added: hook.qc
  12. //--------------------------------------------------------------------
  13. // File: Client.qc
  14. // Procedure: PlayerPreThink
  15. // Location: after line "WaterMove ();"
  16. // Added: CheckGrapHook ();
  17. //--------------------------------------------------------------------
  18. // File: World.qc
  19. // Procedure: worldspawn
  20. // Location: after line "precache_model ("progs/s_spike.mdl");"
  21. // Added: precache_model ("progs/hook.mdl");
  22. //        precache_model ("progs/bit.mdl");
  23. //--------------------------------------------------------------------
  24. // File: Weapons.qc
  25. // Procedure: W_Precache
  26. // Location: end of procedure
  27. // Added: precache_sound ("shambler/smack.wav");
  28. //        precache_sound ("blob/land1.wav");
  29. //        precache_sound ("hook/chain1.wav");
  30. //        precache_sound ("hook/chain2.wav");
  31. //        precache_sound ("hook/retract.wav");
  32. //--------------------------------------------------------------------
  33. // File: Defs.qc
  34. // Declaration group: player only fields
  35. // Location: after line ".float pain_finished;"
  36. // Added: .float hook;    
  37. //--------------------------------------------------------------------
  38.  
  39.  
  40. void(vector org, vector vel, float damage) SpawnBlood;    // prototype
  41. float () crandom;                               // prototype
  42.  
  43.  
  44. float    HOOK_OUT     = 1;        // bit flag on if hook has been launched
  45. float    HOOK_ON     = 2;        // bit flag on if hook command is active
  46. float SHRINK_ON     = 4;        // bit flag on if shrink chain is active
  47. float GROW_ON     = 8;        // bit flag on if grow chain is active
  48. // Rob; used to stop auto shrink if action key released prior to hit
  49. float    HOOK_SG_STOP     = 16;
  50.  
  51.  
  52.  
  53. // impulse constants
  54. float I_HOOK         = 98;
  55. float    I_GROW         = 97;
  56. float    I_SHRINK         = 96;
  57. float    I_STOP         = 95;
  58.  
  59. float MIN_CHAIN_LEN     = 40;        // minimum chain length
  60. float MAX_CHAIN_LEN     = 1000;    // maximum chain length
  61. float GROW_SHRINK_RATE     = 40;        // speed of chain growth/shrink
  62.  
  63.  
  64. //--------------------------------------------------------------------
  65. // Vector dot product function
  66. //--------------------------------------------------------------------
  67. float (vector from, vector onto) Dot =
  68. {
  69.     return from_x * onto_x + from_y * onto_y + from_z * onto_z;
  70. };
  71.  
  72.  
  73. //--------------------------------------------------------------------
  74. // Removes hook and detaches player
  75. //--------------------------------------------------------------------
  76. void () DropHook =
  77. {
  78.         local entity linkptr;
  79.         local entity nextptr;
  80.  
  81.     // remove all hook flags
  82.     self.owner.hook = 0;
  83.  
  84.     // removes chain
  85.     linkptr = self.goalentity;
  86.     while (linkptr != world)
  87.     {
  88.         nextptr = linkptr.goalentity;
  89.         remove (linkptr);
  90.         linkptr = nextptr;
  91.     }
  92.  
  93.     sound (self.owner, CHAN_AUTO, "hook/retract.wav", 1, ATTN_NORM);
  94.  
  95.     // removes hook
  96.     remove (self);
  97. };
  98.  
  99.  
  100. //--------------------------------------------------------------------
  101. // Updated calculation of link positions
  102. //--------------------------------------------------------------------
  103. void () LinkPos =
  104. {
  105.     setorigin (self, self.owner.origin + ((self.enemy.origin + '0 0 16') - self.owner.origin) * self.weapon);
  106.     self.nextthink = time + 0.01;
  107. };
  108.  
  109.  
  110. //--------------------------------------------------------------------
  111. // Creates chain
  112. //--------------------------------------------------------------------
  113. entity (entity head, entity tail, float num) CreateChain =
  114. {
  115.     local entity link, prevlink;
  116.     local float linknum;
  117.  
  118.     linknum = num;
  119.     num = num + 1;
  120.     prevlink = world;
  121.     while (linknum > 0)
  122.     {
  123.         link = spawn();
  124.         link.goalentity = prevlink;
  125.         prevlink = link;
  126.         link.owner = head;
  127.         link.enemy = tail;
  128.         link.weapon = linknum / num;
  129.         link.movetype = MOVETYPE_NOCLIP;
  130.         link.solid = SOLID_NOT;
  131.         link.angles_z = 51 * linknum;
  132.         link.angles_y = 41 * linknum;
  133.         link.angles_x = 31 * linknum;
  134.         link.avelocity = '310 410 510';
  135.         setmodel (link, "progs/bit.mdl");
  136.         setsize (link, '0 0 0', '0 0 0');
  137.         setorigin (link, head.origin + ((tail.origin + '0 0 16') - head.origin) * link.weapon);
  138.         link.nextthink = time + 0.01;
  139.         link.think = LinkPos;
  140.         linknum = linknum - 1;
  141.     }
  142.     return link;
  143. };
  144.  
  145.  
  146. //--------------------------------------------------------------------
  147. // Hook behavior function
  148. //--------------------------------------------------------------------
  149. void () HookBehavior =
  150. {
  151.         local vector spray;                // for blood
  152.         local vector chainvec;                // chain vector
  153.     local vector velpart;                // player velocity moving away from hook
  154.     local float chainlength;            // length of extended chain
  155.     local float f1;                    // antigravity force
  156.     local float i1, i2;                // intermediate values
  157.  
  158.     self.nextthink = time + 0.1;
  159.  
  160.     // decide when to disconnect hook
  161.     if ( !(self.owner.hook & HOOK_ON)  ||
  162.         (self.owner.teleport_time > time) ||     // if player goes through teleport
  163.         self.owner.deadflag ||            // if player dies
  164.         (self.enemy.solid == SOLID_NOT)    )    // if target dies
  165.     {
  166.         DropHook();
  167.         return;
  168.     }
  169.  
  170.     // give some damage to entities that take damage
  171.     if (self.enemy.takedamage)
  172.         T_Damage (self.enemy, self, self.owner, 3);
  173.  
  174.     // when hook hits player add blood and sounds
  175.     if (self.enemy.solid == SOLID_SLIDEBOX)
  176.     {
  177.         sound (self, CHAN_AUTO, "blob/land1.wav", 0.8, ATTN_NORM);
  178.         spray_x = 100 * crandom();
  179.         spray_y = 100 * crandom();
  180.         spray_z = 100 * crandom() + 50;
  181.         SpawnBlood (self.origin, spray, 20);
  182.         setorigin (self, self.enemy.origin + self.enemy.mins + self.enemy.size * 0.5);
  183.     }
  184.  
  185.     self.velocity = self.enemy.velocity;
  186.  
  187. // chain physics
  188.  
  189.     chainvec = self.origin - (self.owner.origin + '0 0 16');
  190.     chainlength = vlen (chainvec);
  191.  
  192.     // Rob; changed shrink and grow structures
  193.     // trivial things to make the formula work bug-free with QC
  194.     // (You find this in a book, Bort?  Otherwise you're a freagin
  195.     // math wizard :-)
  196.     if ( (self.owner.hook & GROW_ON) )
  197.     {
  198.         if ( (self.owner.flags & FL_ONGROUND) )
  199.             self.armorvalue = chainlength;
  200.         else
  201.         {
  202.             self.armorvalue = self.armorvalue + GROW_SHRINK_RATE;
  203.             sound (self.owner, CHAN_AUTO,
  204.                 "hook/chain1.wav", 0.8, ATTN_NORM);
  205.         }
  206.         if ( self.armorvalue > MAX_CHAIN_LEN )
  207.             self.armorvalue = MAX_CHAIN_LEN;
  208.     }
  209.     // shrink the length of the chain
  210.     if ( (self.owner.hook & SHRINK_ON) )
  211.     {
  212.  
  213.         // fixes not raising when directly under the hook
  214.         self.owner.flags = self.owner.flags -
  215.                                  (self.owner.flags & FL_ONGROUND);
  216.         self.armorvalue = self.armorvalue - GROW_SHRINK_RATE;
  217.  
  218.         if (self.armorvalue < MIN_CHAIN_LEN)
  219.             self.armorvalue = MIN_CHAIN_LEN;
  220.         else
  221.             sound (self.owner, CHAN_AUTO,
  222.                 "hook/chain2.wav", 0.8, ATTN_NORM);
  223.     }
  224.  
  225.  
  226.     // if player's location is beyond the chain's reach
  227.     if (chainlength > self.armorvalue)
  228.     {
  229.         // derives force towards hook
  230.             f1 = (chainlength - self.armorvalue) * 3;
  231.  
  232.         // determine player's velocity part moving away from hook
  233.         i1 = Dot(self.owner.velocity,chainvec);
  234.         i2 = Dot(chainvec,chainvec);
  235.         velpart = chainvec * (i1 / i2);
  236.  
  237.         // get magnitude(tug on chain) of velpart
  238.         i1 = vlen (velpart);
  239.  
  240.         // if hard tug on the chain add a bounce
  241.         if (i1 > 450) velpart = velpart * 1.35;
  242.  
  243.         // apply chain restrainment
  244.         self.owner.velocity = self.owner.velocity - velpart;
  245.  
  246.         // if harder tug on chain, then inflict pain
  247.         if (i1 > 900)
  248.         {
  249.             T_Damage (self.owner, world, world, 5);
  250.             sound (self.owner, CHAN_VOICE, "player/land2.wav", 1, ATTN_NORM);
  251.         }
  252.     }
  253.     else
  254.         f1 = 0;
  255.  
  256.         // applys forces to players velocity
  257.     self.owner.velocity = self.owner.velocity + normalize(chainvec) * f1;
  258.  
  259. };
  260.  
  261.  
  262. //--------------------------------------------------------------------
  263. // Hook's touch function
  264. //--------------------------------------------------------------------
  265. void() ChainTouch =
  266. {
  267.     if (!(self.owner.hook & HOOK_ON))
  268.     {
  269.         DropHook();
  270.         return;
  271.     }
  272.  
  273.     if (other.takedamage)
  274.         T_Damage (other, self, self.owner, 10 );
  275.  
  276.     if (other.solid == SOLID_SLIDEBOX)
  277.     {
  278.         sound (self, CHAN_AUTO, "shambler/smack.wav", 1, ATTN_NORM);
  279.         SpawnBlood (self.origin, self.velocity, 10);
  280.         setorigin (self, other.origin + other.mins + other.size * 0.5);
  281.     }
  282.     else
  283.     {
  284.         sound (self, CHAN_AUTO, "player/axhit2.wav", 1, ATTN_NORM);
  285.         self.avelocity = '0 0 0';
  286.     }
  287.  
  288.     self.velocity = other.velocity;
  289.  
  290.     // Rob
  291.     if (! (self.owner.hook & HOOK_SG_STOP) )
  292.         self.owner.hook = self.owner.hook | SHRINK_ON;
  293.  
  294.     self.enemy = other;
  295.     self.nextthink = time + 0.1;
  296.     self.think = HookBehavior;
  297.     self.touch = SUB_Null;
  298. };
  299.  
  300.  
  301. //--------------------------------------------------------------------
  302. // Limit hook length during launch
  303. //--------------------------------------------------------------------
  304. void() LaunchHook =
  305. {
  306.         local vector chainvec;                // chain vector
  307.     local float chainlength;            // length of extended chain
  308.  
  309.     chainvec = self.origin - (self.owner.origin + '0 0 16');
  310.     chainlength = vlen (chainvec);
  311.  
  312.     // armorvalue is used to hold current length of chain
  313.     self.armorvalue = chainlength;
  314.  
  315.     // Rob; added death check
  316.     if (chainlength > MAX_CHAIN_LEN ||
  317.          self.owner.solid == SOLID_NOT)
  318.     {
  319.         DropHook();
  320.         return;
  321.     }
  322.  
  323.     self.nextthink = time + 0.1;
  324. };
  325.  
  326.  
  327. //--------------------------------------------------------------------
  328. // Initiates the hook
  329. //--------------------------------------------------------------------
  330. void(entity myself) InitiateHook =
  331. {
  332.     local entity newhook;
  333.  
  334.     newhook = spawn ();
  335.     newhook.owner = myself;
  336.     newhook.movetype = MOVETYPE_FLY;
  337.     newhook.solid = SOLID_BBOX;
  338.     setmodel (newhook, "progs/hook.mdl");
  339.     setsize (newhook, '0 0 0', '0 0 0');
  340.     makevectors (myself.v_angle);
  341.     setorigin (newhook, myself.origin + (v_forward*16) + '0 0 16' );
  342.     newhook.velocity = v_forward*1000;
  343.     newhook.angles = vectoangles(newhook.velocity);
  344.     newhook.avelocity = '0 0 600';
  345.     sound (myself, CHAN_AUTO, "weapons/ax1.wav", 1, ATTN_NORM);
  346.     newhook.goalentity = CreateChain (newhook, myself, 8);
  347.  
  348.     newhook.touch = ChainTouch;
  349.     newhook.nextthink = time + 0.1 ;
  350.     newhook.think = LaunchHook;
  351. };
  352.  
  353.  
  354. //--------------------------------------------------------------------
  355. // Checks impulse
  356. //--------------------------------------------------------------------
  357. void() CheckGrapHook =
  358. {
  359.     if (self.impulse == I_HOOK)
  360.     {
  361.         if (!(self.hook & HOOK_OUT) )
  362.         {
  363.             // flags that one instance of hook is spawned
  364.             self.hook = self.hook | HOOK_OUT;
  365.  
  366.             // flags last activated hook impulse as being ON
  367.             self.hook = self.hook | HOOK_ON;
  368.  
  369.             InitiateHook (self);
  370.             return;
  371.         }
  372.     }
  373.  
  374.     if (self.hook & HOOK_ON)
  375.     {
  376.         // release hook
  377.         if (self.impulse == I_HOOK)
  378.         {
  379.             self.hook = self.hook - (self.hook & HOOK_ON);
  380.             return;
  381.         }
  382.  
  383.         // hop of chain and release hook
  384.         if (    (self.button2) &&
  385.             (!(self.flags & FL_ONGROUND)) &&
  386.             (self.flags & FL_JUMPRELEASED) &&
  387.             (!(self.flags & FL_INWATER))    )
  388.         {
  389.             self.hook = self.hook - (self.hook & HOOK_ON);
  390.             self.velocity_z = self.velocity_z + 200;
  391.             sound (self, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM);
  392.             return;
  393.         }
  394.  
  395.         // deactivate chain growth or shrink
  396.         if (self.impulse == I_STOP)
  397.         {
  398.             self.hook = self.hook | HOOK_SG_STOP; // Rob
  399.             self.hook = self.hook - (self.hook & GROW_ON);
  400.             self.hook = self.hook - (self.hook & SHRINK_ON);
  401.             return;
  402.         }
  403.  
  404.         // activate chain growth
  405.         if (self.impulse == I_GROW)
  406.         {
  407.             self.hook = self.hook | GROW_ON;
  408.             self.hook = self.hook - (self.hook & SHRINK_ON);
  409.             return;
  410.         }
  411.  
  412.         // activate chain shrinking
  413.         if (self.impulse == I_SHRINK)
  414.         {
  415.             self.hook = self.hook | SHRINK_ON;
  416.             self.hook = self.hook - (self.hook & GROW_ON);
  417.         }
  418.     }
  419. };